package com.dbw.englishassistant.ui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

import com.dbw.englishassistant.service.Sentence;
import com.dbw.englishassistant.service.SentenceParser;
import com.dbw.englishassistant.service.SentenceParserFactory;
import com.dbw.englishassistant.ui.tool.GridBagLayoutTool;
import com.dbw.englishassistant.ui.tool.OptionPaneTool;

public class MainFrame extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    private OptionPaneTool optionPaneTool = new OptionPaneTool(this);
    
    private JMenuItem openFileMenuItem = null;
    
    private JTextField zhSentenceTextFiled = null;
    private JTextField enSentenceTextField = null;
    private JTextField inputEnSentenceTextField = null;
    private JTextArea detailTextArea = null;
    
    private JProgressBar progressBar = null;
    
    private JButton showEnButton = null;
    private JButton resetButton = null;
    private JButton resetAllButton = null;
    
    private JButton firstButton = null;
    private JButton previousButton = null;
    private JButton nextButton = null;
    private JButton lastButton = null;
    
    private static class TestData {
        
        private Sentence sentence;
        
        private String inputSentence;
        
        private boolean showEnSentence;
        
        public TestData(Sentence sentence) {
            setSentence(sentence);
            reset();
        }

        public Sentence getSentence() {
            return sentence;
        }

        public void setSentence(Sentence sentence) {
            this.sentence = sentence;
        }

        public String getInputSentence() {
            return inputSentence;
        }

        public void setInputSentence(String inputSentence) {
            this.inputSentence = inputSentence;
        }

        public boolean isShowEnSentence() {
            return showEnSentence;
        }

        public void setShowEnSentence(boolean showEnSentence) {
            this.showEnSentence = showEnSentence;
        }
        
        public void reset() {
            setInputSentence("");
            setShowEnSentence(false);
        }
        
    }
    
    private List<TestData> testDataList = new ArrayList<>();
    
    private int testDataIndex = 0;

    public MainFrame() {
        Container container = getContentPane();
        container.add(createMenu(), BorderLayout.NORTH);
        container.add(createWorkArea(), BorderLayout.CENTER);
        setTitle("英语流利说学习助手");
        setResizable(false);
        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);
    }
    
    private JComponent createMenu() {
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(createFileMenu());
        return menuBar;
    }
    
    private JMenu createFileMenu() {
        JMenu menu = new JMenu("文件");
        menu.add(createOpenFileMenuItem());
        return menu;
    }
    
    private JMenuItem createOpenFileMenuItem() {
        openFileMenuItem = new JMenuItem("打开");
        openFileMenuItem.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                File file = selectFile();
                if(file == null) {
                    return;
                }
                
                try {
                    loadTestData(file);
                    updateWorkArea();
                } catch (Exception ex) {
                    ex.printStackTrace();
                    optionPaneTool.showError("加载文件失败");
                }
                
            }
            
            private File selectFile() {
                
                JFileChooser jfc = new JFileChooser("./data");
                jfc.setApproveButtonText("确认");
                jfc.setDialogTitle("文件选择");
                jfc.addChoosableFileFilter(new FileFilter(){
                    public boolean accept(File f) {
                        if(f.isDirectory()){
                            return true;
                        }
                        return f.getName().endsWith(".md");
                    }
                    public String getDescription() {
                        return new String("md文件(*.md)");
                    }
                });
                jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
                jfc.setMultiSelectionEnabled(false);
                int result = jfc.showOpenDialog(MainFrame.this);
                if(result != JFileChooser.APPROVE_OPTION){
                    return null;
                }
                
                return jfc.getSelectedFile();
            }
        });
        return openFileMenuItem;
    }
    
    private JComponent createWorkArea() {
        
        JComponent workAreaUI = createWorkAreaUI();
        int borderSize = 10;
        workAreaUI.setBorder(BorderFactory.createEmptyBorder(
                borderSize, borderSize, borderSize, borderSize));
        
        setActions();
        updateButtonStatus();
        
        return workAreaUI;
    }
    
    private JComponent createWorkAreaUI() {
        createWorkAreaComponents();
        return createWorkAreaLayout();
    }
    
    private void createWorkAreaComponents() {
        int columns = 50;
        zhSentenceTextFiled = new JTextField(columns);
        zhSentenceTextFiled.setEditable(false);
        enSentenceTextField = new JTextField(columns);
        enSentenceTextField.setEditable(false);
        inputEnSentenceTextField = new JTextField(columns);
        detailTextArea = new JTextArea(10, columns);
        detailTextArea.setEditable(false);
        
        progressBar = new JProgressBar(JProgressBar.HORIZONTAL, 0, 100);
        progressBar.setStringPainted(true);
        progressBar.setValue(0);
        
        showEnButton = new JButton("显示原文");
        resetButton = new JButton("重置");
        resetAllButton = new JButton("全部重置");
        firstButton = new JButton("第一个");
        previousButton = new JButton("上一个");
        nextButton = new JButton("下一个");
        lastButton = new JButton("最后一个");
    }
    
    private JComponent createWorkAreaLayout() {
        
        JPanel areaPanel = new JPanel();
        areaPanel.setLayout(new GridBagLayout());
        Insets insets = new Insets(5, 5, 5, 5);
        
        int y = 0;
        GridBagLayoutTool.add(areaPanel, new JLabel("中文："), 0, y, 0, 0, insets);
        GridBagLayoutTool.add(areaPanel, zhSentenceTextFiled, 1, y, 1, 0, insets);
        y++;
        GridBagLayoutTool.add(areaPanel, new JLabel("原文："), 0, y, 0, 0, insets);
        GridBagLayoutTool.add(areaPanel, enSentenceTextField, 1, y, 1, 0, insets);
        y++;
        GridBagLayoutTool.add(areaPanel, new JLabel("请翻译："), 0, y, 0, 0, insets);
        GridBagLayoutTool.add(areaPanel, inputEnSentenceTextField, 1, y, 1, 0, insets);
        y++;
        GridBagLayoutTool.add(areaPanel, detailTextArea, 0, y, 2, 1,1, 1, insets);
        y++;
        GridBagLayoutTool.add(areaPanel, progressBar, 0, y, 2, 1, 1, 0, insets);
        y++;
        GridBagLayoutTool.add(areaPanel, createButtonLayout(), 0, y, 2, 1, 1, 0);
        y++;
        
        return areaPanel;
    }
    
    private JComponent createButtonLayout() {
        
        Box topBox = Box.createVerticalBox();
        
        int interval = 20;
        Dimension preferredSize = showEnButton.getPreferredSize();
        previousButton.setPreferredSize(preferredSize);
        nextButton.setPreferredSize(preferredSize);
        resetButton.setPreferredSize(preferredSize);
        
        Box navBox = Box.createHorizontalBox();
        navBox.add(Box.createHorizontalGlue());
        navBox.add(firstButton);
        navBox.add(Box.createHorizontalStrut(interval));
        navBox.add(previousButton);
        navBox.add(Box.createHorizontalStrut(interval));
        navBox.add(nextButton);
        navBox.add(Box.createHorizontalStrut(interval));
        navBox.add(lastButton);
        navBox.add(Box.createHorizontalGlue());
        
        Box miscBox = Box.createHorizontalBox();
        miscBox.add(Box.createHorizontalGlue());
        miscBox.add(showEnButton);
        miscBox.add(Box.createHorizontalStrut(interval));
        miscBox.add(resetButton);
        miscBox.add(Box.createHorizontalStrut(interval));
        miscBox.add(resetAllButton);
        miscBox.add(Box.createHorizontalGlue());
        
        topBox.add(navBox);
        topBox.add(Box.createVerticalStrut(10));
        topBox.add(miscBox);
        
        return topBox;
    }
    
    private void setActions() {
        setInputAction();
        setShowEnAction();
        setResetAction();
        setNavAction();
        setResetAllAction();
    }
    
    private void setInputAction() {
        inputEnSentenceTextField.setDocument(new PlainDocument() {
            
            /**
             * 
             */
            private static final long serialVersionUID = 1L;

            @Override
            public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
                super.insertString(offs, str, a);
                saveText(getText(0, getLength()));
            }
            
            private void saveText(String text) {
                TestData testData = getTestData();
                if(testData == null) {
                    return;
                }
                testData.setInputSentence(text);
            }
        });
        
        inputEnSentenceTextField.addKeyListener(new KeyListener() {
            
            @Override
            public void keyTyped(KeyEvent e) {
                if(e.getKeyChar() == '\n') {
                    TestData testData = getTestData();
                    if(testData == null) {
                        return;
                    }
                    if(!testData.isShowEnSentence()) {
                        showEnButton.doClick();
                    } else {
                        nextButton.doClick();
                    }
                }
            }
            
            @Override
            public void keyReleased(KeyEvent e) {
                
            }
            
            @Override
            public void keyPressed(KeyEvent e) {
                
            }
        });
    }
    
    private void setShowEnAction() {
        showEnButton.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                getTestData().setShowEnSentence(true);
                updateWorkArea();
            }
        });
    }
    
    private void setResetAction() {
        resetButton.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                getTestData().reset();
                updateWorkArea();
            }
        });
    }
    
    private void setNavAction() {
        firstButton.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                testDataIndex = 0;
                updateWorkArea();
            }
        });
        previousButton.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                testDataIndex--;
                updateWorkArea();
            }
        });
        
        nextButton.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                testDataIndex++;
                updateWorkArea();
            }
        });
        lastButton.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                testDataIndex = testDataList.size() - 1;
                updateWorkArea();
            }
        });
    }
    
    private void setResetAllAction() {
        resetAllButton.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                if(!optionPaneTool.askForConfirmation("重置将会清除本课复习记录，确认要重置吗？")) {
                    return;
                }
                
                resetTestData();
                updateWorkArea();
            }
        });
    }
    
    private void loadTestData(File file) throws Exception {

        SentenceParser parser = SentenceParserFactory.createSentenceParser();
        String text = new String(Files.readAllBytes(Paths.get(file.getAbsolutePath())));
        List<Sentence> sentenceList = parser.parse(text);
        
        testDataIndex = 0;
        testDataList.clear();
        for(Sentence sentence : sentenceList) {
            TestData testData = new TestData(sentence);
            testDataList.add(testData);
        }
    }
    
    private void resetTestData() {

        testDataIndex = 0;
        for(TestData testData :testDataList) {
            testData.reset();
        }
    }
    
    private TestData getTestData() {
        if(testDataIndex < 0 || testDataIndex > testDataList.size() - 1) {
            return null;
        }
        return testDataList.get(testDataIndex);
    }
    
    private void updateWorkArea() {
        paintTestData();
        updateButtonStatus();
        updateProgress();
    }
    
    private void paintTestData() {
        if(testDataList.isEmpty()) {
            zhSentenceTextFiled.setText("");
            enSentenceTextField.setText("");
            inputEnSentenceTextField.setText("");
            detailTextArea.setText("");
            return;
        }
        
        TestData testData = getTestData();
        Sentence sentence = testData.getSentence();
        zhSentenceTextFiled.setText(sentence.getChineseSentence());
        inputEnSentenceTextField.setText(testData.getInputSentence());
        if(testData.isShowEnSentence()) {
            enSentenceTextField.setText(sentence.getEnglishSentence());
            detailTextArea.setText(sentence.getDetailDescription());
        } else {
            enSentenceTextField.setText("");
            detailTextArea.setText("");
        }
    }
    
    private void updateButtonStatus() {
        if(testDataList.isEmpty()) {
            showEnButton.setEnabled(false);
            resetButton.setEnabled(false);
            resetAllButton.setEnabled(false);
            firstButton.setEnabled(false);
            previousButton.setEnabled(false);
            nextButton.setEnabled(false);
            lastButton.setEnabled(false);
        } else {
            showEnButton.setEnabled(true);
            resetButton.setEnabled(true);
            resetAllButton.setEnabled(true);
            firstButton.setEnabled(testDataIndex > 0);
            previousButton.setEnabled(testDataIndex > 0);
            nextButton.setEnabled(testDataIndex < testDataList.size() - 1);
            lastButton.setEnabled(testDataIndex < testDataList.size() - 1);
        }
    }
    
    private void updateProgress() {
        if(testDataList.isEmpty()) {
            progressBar.setValue(0);
        } else {
            progressBar.setValue((testDataIndex + 1) * 100 / testDataList.size());
        }
        
    }
    
    public static void main(String[] args) {
        new MainFrame();
    }
}
